#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <string.h>
#include <vector>
#include <sys/stat.h>
#include <unistd.h>
#include <fstream>
#include <map>

#include "log.h"
using namespace LOG;
#define SERVER_IP INADDR_ANY  // ip地址 修改时调用函数inet_addr
#define PORT 8080             // 端口号
#define REQUEST_SIZE 1024 * 4 // 请求最大字节数

static const char word_sep[] = " ";            // 请求行分隔符
static const char web_root[] = "wwwroot";      // web根目录
static const char web_index[] = "index.html";  // web首页
static const char http_version[] = "HTTP/1.0"; // http版本
static const char k_v_sep[] = ": ";            // 键值对分隔符

typedef std::string (*server)(std::string request);

class HttpServer
{
private:
    void ListensockfdInit()
    {
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensockfd < 0) // 监听套接字创建失败
        {
            lg(FATAL, "listensockfd create fail!!!");
            exit(1);
        }
        lg(INFO, "listensockfd create success");
    }
    void AddrInit()
    {
        memset(&_serveraddr, 0, sizeof _serveraddr);
        _serveraddr.sin_addr.s_addr = SERVER_IP;
        _serveraddr.sin_family = AF_INET;
        _serveraddr.sin_port = htons(PORT);
    }
    void Bind()
    {
        int Judge = bind(_listensockfd, (struct sockaddr *)&_serveraddr, sizeof _serveraddr);
        if (Judge < 0)
        {
            lg(FATAL, "bind fail!!!");
            exit(2);
        }
        lg(INFO, "bind success");
    }
    void Listen()
    {
        int Judge = listen(_listensockfd, 8);
        if (Judge < 0)
        {
            lg(FATAL, "listen status set fail!!!");
            exit(3);
        }
        lg(INFO, "listen status set success");
    }
    void Recv(int sockfd)
    {
        char buffer[REQUEST_SIZE];
        int Judge = recv(sockfd, (void *)buffer, sizeof buffer, 0);
        if (Judge < 0) // 接收失败
        {
            lg(FATAL, "recv message fail!!!");
            exit(4);
        }
        _request = buffer;
    }
    void Path()
    {
        // 获取原始path
        int pos1 = _request.find(word_sep);
        int pos2 = _request.find(word_sep, pos1 + 1);
        std::string path = _request.substr(pos1 + 1, pos2 - pos1 - 1);
        // 查找是否有插入的服务
        auto it = _ser_list.find(path);
        if (it != _ser_list.end()) // 找到了
        {
            lg(DEBUG, "have a inserted server will be start");
            (it->second)(path);
        }

        if (path == "/")
        {
            path.append(web_index);
        }
        // 增加web根目录
        _path = web_root + path;
        // printf("%s\n", _path.c_str());
    }
    void SetRespond(int sockfd)
    {
        // 设置响应
        AddVersion(http_version); // 1.设置http版本

        AddCode(200, "OK"); // 2.设置状态码

        AddData(sockfd); // 3.获取网页内容

        AddKeyValue("Content-Length", std::to_string(_hander_data.size()).c_str()); // 4.设置响应报头

        RespondInit(); // 5.拼接完整应答
    }
    void AddVersion(const char http_v[])
    {
        _hander_status.clear();
        _hander_status = http_v;
        _hander_status += " ";
        // printf("%s",_hander_status);
    }
    void AddCode(int code, const char code_des[])
    {
        if (_falt_code == 1) // 没设置过
        {
            _hander_status += std::to_string(code);
            _hander_status += " ";
            _hander_status += code_des;
            _hander_status += "\r\n";
        }
        else // 设置过
        {
            return;
        }
        // printf("%s",_hander_status.c_str());
    }

    void AddData(int sockfd)
    {
        _hander_data.clear();
        // 获得Cookie，否则只能访问'wwwroot\index.html'资源
        if (strcmp(_path.c_str(), "wwwroot/index.html") != 0) // 不是首页
        {
            // 获取Cookie
        }
        else
        {
            std::ifstream in(_path.c_str(), std::ios::binary);
            if (!in.is_open())
                send(sockfd, "NOT FIND", 9, 0);
            else
            {
                // 获得文件大小
                struct stat file_info;
                stat(_path.c_str(), &file_info);
                size_t filesize = file_info.st_size;

                // 获取文件内容
                char buffer[filesize + 1];
                in.read(buffer, filesize);
                buffer[filesize] = 0;

                // 把文件内容放入_hander_data
                _hander_data.append(buffer, filesize); // 如果文本中有0，直接赋值后面的数据会丢失
            }
            // 关闭文件
            in.close();
        }
    }
    void RespondInit()
    {
        _respond.clear();
        _respond.resize(_hander_data.size());
        _respond = _hander_status;
        _respond += _hander_lines;
        _respond += "\r\n"; // 空行
        _respond += _hander_data;
    }
    void Send(int sockfd)
    {
        printf("----------------------------------\n");
        printf("%s\n", _respond.c_str());
        printf("----------------------------------\n");

        // 发送数据
        ssize_t total_sent = 0;
        ssize_t bytes_left = _respond.size();
        const char *data_ptr = _respond.c_str();

        while (bytes_left > 0)
        {
            ssize_t bytes_sent = send(sockfd, data_ptr + total_sent, bytes_left, 0);
            if (bytes_sent == -1)
            {
                perror("send");
                break;
            }
            total_sent += bytes_sent;
            bytes_left -= bytes_sent;
        }
    }
    std::string GetContent()
    {
        // 得到正文长度
        lg(DEBUG, "%s", _request.c_str());
        size_t pos_2 = _request.find("Content-Length");
        size_t pos_3 = _request.find(" ", pos_2);
        size_t pos_4 = _request.find("\r\n", pos_3);

        size_t len = atoi((_request.substr(pos_3 + 1, pos_4 - pos_3 - 1)).c_str());
        // 得到正文
        size_t pos_1 = _request.rfind("\r\n");
        // lg(DEBUG,"len: %d con: %s",len,_request.substr(pos_1 + 2).c_str());
        std::string ret = _request.substr(pos_1 + 2);
        return ret;
    }
    void Server(int sockfd)
    {
        pid_t id_1 = fork();
        if (id_1 == 0) // 子进程
        {
            close(_listensockfd);
            pid_t id_2 = fork();
            if (id_2 == 0) // 子进程的子进程提供服务
            {
                // 接收请求
                Recv(sockfd);
                // 编辑路径 && 执行插入的服务（如果有）
                Path();
                // 设置响应
                SetRespond(sockfd);
                // 发送响应
                Send(sockfd);
                close(sockfd);
                exit(0);
            }
            else // 子进程
            {
                exit(0);
            }
        }
        else // 父进程
        {
            close(sockfd);
            // 回收子进程
            waitpid(id_1, nullptr, 0);
        }
    }
    void AddKeyValue(const char key[], const char value[])
    {
        _hander_lines += key;
        _hander_lines += ": ";
        _hander_lines += value;
        _hander_lines += "\r\n";
        // printf("%s",_hander_lines.c_str());
    }
    std::vector<std::string> GetUsernamepd()
    {
        std::string content = GetContent();
        size_t pos_1 = content.find("=");
        size_t pos_2 = content.find("&");
        size_t pos_3 = content.rfind("=");

        std::string username = content.substr(pos_1 + 1, pos_2 - pos_1 - 1);
        std::string userpd = content.substr(pos_3 + 1, content.npos - pos_3 - 1);
        std::vector<std::string> ret;
        ret.push_back(username);
        ret.push_back(userpd);
        return ret;
    }

    //-----------------------------------------------------------

    friend std::string login(std::string path); // 友元函数

    //-----------------------------------------------------------

public:
    HttpServer() : _listensockfd(-1)
    {
        // 初始化listensockfd
        ListensockfdInit();
        // 初始化服务器信息
        AddrInit();
        // 绑定
        Bind();
        // 设定为listen状态
        Listen();
    }
    // 获取连接 && 响应请求
    void Start()
    {
        while (true)
        {
            struct sockaddr_in client;
            memset(&client, 0, sizeof client);
            socklen_t len = sizeof client;
            int sockfd = accept(_listensockfd, (struct sockaddr *)&client, &len);
            if (sockfd > 0) // 获取连接成功
            {
                // 单独提供服务
                Server(sockfd);
            }
        }
    }
    void InsertServer(std::string path, server s)
    {
        _ser_list[path] = s; // 插入服务
    }

    ~HttpServer()
    {
    }

private:
    int _listensockfd;                       // 监听套接字
    std::string _request;                    // 客户端请求
    std::string _path;                       // 请求路径
    int _falt_code = 1;                      // 是否设置过状态码
    struct sockaddr_in _serveraddr;          // 服务器IP、端口
    std::string _hander_status;              // 响应状态行
    std::string _hander_lines;               // 响应报头
    std::string _hander_data;                // 响应正文
    std::string _respond;                    // 完整响应
    std::map<std::string, server> _ser_list; // 添加的功能
};
